/** * This code is part of the Bumpslide Library by David Knape * http://bumpslide.com/ *  * Copyright (c) 2006, 2007, 2008 by Bumpslide, Inc. *  * Released under the open-source MIT license. * http://www.opensource.org/licenses/mit-license.php * see LICENSE.txt for full license terms */ package com.bumpslide.ui {	import flash.geom.Rectangle;
	import flash.display.DisplayObject;
	import com.bumpslide.data.type.Padding;	import com.bumpslide.ui.skin.default.DefaultButtonSkin;
	import com.bumpslide.util.Delegate;	import flash.events.Event;	import flash.events.FocusEvent;	import flash.events.KeyboardEvent;	import flash.events.MouseEvent;	import flash.ui.Keyboard;	import flash.utils.Timer;	/**	 * Base Class for Buttons	 * 	 * This is a generic button with disabled and selected states.	 * By default, setting this class as the base class for your buttons	 * will work as expected if you mark your frames with	 * 'off', 'over', 'down', 'selected', and 'disabled'	 * 	 * Alternatively, you can override the protected display/skin methods:	 * _off, _over, _down, _selected, and _disabled to do what you want.  	 * 	 * @author David Knape	 */	public class Button extends Component {
		static public var DefaultSkinClass:Class = DefaultButtonSkin;		static public const STATE_OFF:String = 'off';		static public const STATE_OVER:String = 'over';		static public const STATE_SELECTED:String = 'selected';		static public const STATE_DISABLED:String = 'disabled';		static public const STATE_DOWN:String = 'down';		public static const EVENT_UPDATE:String = "buttonUpdate";  		protected var _isSelected:Boolean = false;		protected var _isMouseOver:Boolean = false;		protected var _isMouseDown:Boolean = false;		protected var _hasFocus:Boolean = false;  				protected var _focusStateEnabled:Boolean = false;		protected var _rollOutDelay:Number = 0;		protected var _rollOutTimer:Timer;		protected var _toggle:Boolean = false;		protected var _selectOnClick:Boolean = false;
		protected var _label:String;		private var _padding:*;
		public function Button( width:Number=100, height:Number=20, x:Number=0, y:Number=0, lbl:String="", defaultClickHandler:Function=null) {						// don't overwrite values set from stage placement in Flash			if(_width==-1) _width = width;			if(_height==-1) _height = height;			if(x!=0) this.x = x;			if(y!=0) this.y = y;			if(lbl!="") label = lbl;			if(defaultClickHandler!=null) {				addEventListener( MouseEvent.CLICK, defaultClickHandler );			}		}				/**		 * Component initialization (provides initButton hook)		 */		override protected function init():void {			stop();			initButton();							super.init();		}				override protected function postConstruct():void 		{
			super.postConstruct();			if(skin==null && skinClass==null) {				skinClass = DefaultSkinClass;			}
		}
				override protected function initSize():void {			super.initSize();			minHeight = 4;			minWidth = 4;		}
		/**		 * Initialized button event handlers		 */		protected function initButton():void {						buttonMode = true;			mouseChildren = false;			focusRect = false;			delayUpdate = false;						addEventListener(MouseEvent.ROLL_OVER, handleRollOver);        				addEventListener(MouseEvent.ROLL_OUT, handleRollOut);  			addEventListener(MouseEvent.MOUSE_DOWN, handleMouseDown);			addEventListener(MouseEvent.CLICK, handleClick, false, 999);			addEventListener(FocusEvent.FOCUS_IN, handleFocusIn);			addEventListener(FocusEvent.FOCUS_OUT, handleFocusOut);						// render children when they are added (needed for certain frame-based state changes)			//addEventListener(Event.ADDED, render);		}
		/**		 * Update skin state based on other properties of this component prior to drawing the skin		 */ 		override protected function draw():void {				if(!enabled) {				_skinState = STATE_DISABLED;			} else if (mousePressed) {				_skinState = STATE_DOWN;			} else if (selected) {				_skinState = STATE_SELECTED;			}  else if (mouseOver || (hasFocus && focusStateEnabled)) {				_skinState = STATE_OVER;			} else {				_skinState = STATE_OFF;			}						super.draw(); 		}		//-----------------------		// MOUSE EVENT HANDLERS		//-----------------------		protected function handleRollOver( event:MouseEvent = null):void {			Delegate.cancel(_rollOutTimer);			_isMouseOver = true;			invalidate();		}
		protected function handleRollOut( event:MouseEvent = null):void {			_isMouseOver = false;			Delegate.cancel(_rollOutTimer);			if(_rollOutDelay > 0) _rollOutTimer = Delegate.callLater(rollOutDelay, doRollOut);            else doRollOut();            		}
		protected function handleMouseDown(event:MouseEvent = null):void {			_isMouseOver = true;			_isMouseDown = true;			if(stage) stage.addEventListener(MouseEvent.MOUSE_UP, handleMouseUp, false, 0, true);			invalidate();		}
		protected function handleMouseUp(event:MouseEvent = null):void {			_isMouseDown = false;			if(stage) stage.removeEventListener(MouseEvent.MOUSE_UP, handleMouseUp);			invalidate();		}
		protected function handleClick(event:MouseEvent = null):void {			_isMouseDown = false;			if(stage) stage.removeEventListener(MouseEvent.MOUSE_UP, handleMouseUp);			if(toggle) {				selected = !selected;			} else if(selectOnClick) {				selected = true;			}		}		protected function handleFocusIn(event:FocusEvent):void {			_hasFocus = true;			addEventListener(KeyboardEvent.KEY_DOWN, handleKeyPress);			invalidate();		}		protected function handleFocusOut(event:FocusEvent):void {			_hasFocus = false;			addEventListener(KeyboardEvent.KEY_DOWN, handleKeyPress);			invalidate();		}		protected function handleKeyPress(event:KeyboardEvent):void {			if(event.keyCode == Keyboard.ENTER) {				if(toggle) {					selected = !selected;				} else if(selectOnClick) {					selected = true;				}			}		}		protected function doRollOut():void {        				handleMouseUp();			invalidate();		}		//-----------------------------		// GETTERS/SETTERS		//-----------------------------		override public function set enabled( buttonEnabled:Boolean ):void {			if(!buttonEnabled) _isMouseOver = false;  			useHandCursor = buttonEnabled;			mouseEnabled = buttonEnabled;			super.enabled = buttonEnabled;		}
		public function get selected():Boolean {			return _isSelected;		}
		public function set selected(val:Boolean):void {			if(_isSelected == val) return;			_isSelected = val;			_isMouseOver = false;			dispatchEvent(new Event(Event.CHANGE, true));						sendChangeEvent( 'selected', val, !val);					invalidate();		}
		/**		 * Time from rollout event to 		 */		public function get rollOutDelay():Number {			return _rollOutDelay;		}
		public function set rollOutDelay(rollOutDelay:Number):void {			_rollOutDelay = rollOutDelay;		}
		public function get mouseOver():Boolean {			return _isMouseOver;		}
		public function get mousePressed():Boolean {			return _isMouseDown;		}
		public function get toggle():Boolean {			return _toggle;
		}
		/**		 * toggle selection status when clicked		 */
		public function set toggle(toggle:Boolean):void {			_toggle = toggle;
		}
		public function get selectOnClick():Boolean {			return _selectOnClick;		}
		/**		 * automatically make button selected when it is clicked		 * 		 * Unlike toggleButton, this does not change state back to off when selected again. 		 * This is used for radio button and tab select buttons that don't have state driven 		 * by a model binding.		 * 		 * If toggle is true, this setting is ignored.		 */		public function set selectOnClick(selectOnClick:Boolean):void {			_selectOnClick = selectOnClick;		}		/**		 * Whether or not the button currently has input focus		 */		public function get hasFocus():Boolean {			return _hasFocus;		}				/**		 * Whether or not to show overState when focused		 */		public function get focusStateEnabled():Boolean {			return _focusStateEnabled;		}				public function set focusStateEnabled(focusEnabled:Boolean):void {			_focusStateEnabled = focusEnabled;		}				/**		 * The label string		 */		public function get label():String {			return _label;		}				public function set label(label:String):void {			_label = label;			invalidate();		}				public function get padding():Padding {			return _padding;		}				/**		 * padding around content		 * 		 * This value is passed directly to the label in the default button skin.		 */		public function set padding ( p:* ) : void {			if(p is Padding) _padding = (p as Padding).clone();			else _padding = Padding.fromString( String(p) );			invalidate();		}				override public function get width():Number {			if(_width==0) {				return actualWidth;			} else {				return super.width;			}		}	}}